package it.univpm.diiga.memorysim.kernel.shared;

import it.univpm.diiga.memorysim.kernel.CPU;
import it.univpm.diiga.memorysim.kernel.IMemoryElement;
import it.univpm.diiga.memorysim.kernel.MAIN;
import it.univpm.diiga.memorysim.kernel.shared.tree.MovingBox;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

public class Kernel {

	private Parameters p= new Parameters();
	
	private ArrayList<SimEvent> events=new ArrayList<SimEvent>();
	private EventsDisk eventsDisk=new EventsDisk();
		
	
	private boolean SimType1=false,SimType2=false;
	
	public Kernel(){	
		
		//MAIN.main(null);
		Parameters.loadAlgorithm();
		//Parameters.setAlgorithmSelectedPag(1);
		
	}
	
	public String[] getAlgorithmSecMem(){
		
		String[] listAlgo=new String[Parameters.getAlgorithmListHDD().size()];
		
		for(int i=0;Parameters.getAlgorithmListHDD()!=null && 
										i<Parameters.getAlgorithmListHDD().size();i++){
			
			listAlgo[i]=Parameters.getAlgorithmListHDD().get(i).getAlgorithmName();
			
		}
	return listAlgo;
	}
	
	public String[] getAlgorithmCentMemPag(){
	
		String[] listAlgo=new String[Parameters.getAlgorithmListPag().size()];
		
			for(int i=0;Parameters.getAlgorithmListPag()!=null && 
										i<Parameters.getAlgorithmListPag().size();i++){
			
			listAlgo[i]=Parameters.getAlgorithmListPag().get(i).getAlgorithmName();
			
		}
			
		return listAlgo;
	
	}
	
	public String[] getAlgorithmCentMemSeg(){
		
		String[] listAlgo=new String[Parameters.getAlgorithmListSeg().size()];
		
			for(int i=0;Parameters.getAlgorithmListSeg()!=null && 
										i<Parameters.getAlgorithmListSeg().size();i++){
			
			listAlgo[i]=Parameters.getAlgorithmListSeg().get(i).getAlgorithmName();
			
		}
			
		return listAlgo;
	
	}
	
	public void activeSimType1(){
		System.out.println("SIMULAZIONE TIPO1 ATTIVA");
		SimType1=true;
	}
	
	public void activeSimType2(){
		System.out.println("SIMULAZIONE TIPO2 ATTIVA");
		SimType2=true;
	}
	
	public void setDimSOMemory(int mem){
		System.out.println("Memoria Sistema Operativo: "+mem);
		p.setDimSOMemory(mem);
	}

	public boolean isactiveSimType1() {
		return SimType1;
	}
	public boolean isactiveSimType2() {
		return SimType2;
	}

	public void selectedAlgorithmSecMem(String algSelected) {
		System.out.println("Algorimtmo Selezionato: "+algSelected);
		
	}
	
	public void selectedAlgorithmSecMem(int algSelected) {
		System.out.println("Algorimtmo Selezionato: "+algSelected);
		p.setAlgorithmSelectedHDD(algSelected);
	}
	

	public void selectedAlgorithmCentMem(String algSelected) {
		System.out.println("Algorimtmo Selezionato: "+algSelected);
	}
	
	public void selectedAlgorithmCentMem(int algID, boolean isPag) {
		System.out.println("Algorimtmo Selezionato: "+algID);
		if(isPag){Parameters.setDimensionBlock(1);
			p.setAlgorithmSelectedPag(algID);}
		else{p.setDimensionBlock(0);
			p.setAlgorithmSelectedSeg(algID);}
	}
	

	public void setHardware(int memorycentraldata,int swapdata,int blockdata,int hdddimensiondata,int trasferratedata,
			int seekdata,int revolutiontimedata, int hdddimensionblockdata) {
		System.out.println("Caratteristiche Hardware configurate!!");
		System.out.println("dimmem:"+memorycentraldata);
		
		p.setDimensionCentralMemory(memorycentraldata*1024);
		p.setDimensionSwap(swapdata*1024);
		if(p.isPagination())p.setDimensionBlock(blockdata);
		p.setSecondaryMemory(hdddimensiondata, seekdata, hdddimensionblockdata, trasferratedata, revolutiontimedata);
	}

	public void setListProcess(ArrayList<Process> listProcess, ArrayList<String> centralMemoryP, ArrayList<String> swapMemoryP) {
		System.out.println("Lista dei Processi Importati");
		p.setProcesses(listProcess);
		p.memstart(centralMemoryP,swapMemoryP);
	}

	public void setListProcessRequest(ArrayList<ProcessRequest> listProcessRequest){
		System.out.println("Richieste di Processi Importate");
		p.setProcessList(listProcessRequest);
	}

	public void setFileSystem(MovingBox root) {
		System.out.println("File System Importato");
		Parameters.setFileSystem(root);
	}

	public void setListFileRequest(ArrayList<FileRequest> listFileRequest) {
		Parameters.setFileList(listFileRequest);
		System.out.println("Richieste di File Importate");
	}
	
	public void start_simulation(){
		//TABELLA EVENTI MEMORIA

		events=new ArrayList<SimEvent>();
		
		if (isactiveSimType1()){
			
			
			Parameters.setSimulationType(1);
			
			CPU cpu = new CPU();
			System.out.println(Parameters.getProcessList().size());
		
			
			System.out.println("\n\n\ndimcentmem:"+p.getDimMemory()+"\nsimtype:"+p.getSimulationType()+"\nalgo:"+p.getDimPage()+"\n");
			for(int i=0;i<p.getProcessList().size();i++){
				
			
				System.out.println(p.getProcessList().get(i).toString());
				
			}
			
			
			try{
				cpu.dispacher();	
			}catch(Exception e){
				e.printStackTrace();
			}
			
			
			System.out.println("--------------------------------TERMINE DELLA SIMULAZIONE------num event: "+Parameters.getEventMem().size());
			
			
			for (int i=0;i<Parameters.getEventMem().size();i++){
				System.out.println(Parameters.getEventMem().get(i).getEventType());
			
				Hashtable<Integer, ProcessRequest> mem = new Hashtable<Integer, ProcessRequest>();
				Hashtable<Integer, ProcessRequest> swap = new Hashtable<Integer, ProcessRequest>();
				IMemoryElement ele;
				for(int j=0;j<Parameters.getEventMem().get(i).getMemorySituation().size();j++){
					System.out.println(Parameters.getEventMem().get(i).getMemorySituation().get(j).getStart());
					System.out.println(Parameters.getEventMem().get(i).getMemorySituation().get(j).isEmpty());
					System.out.println(Parameters.getEventMem().get(i).getMemorySituation().get(j).getEnd());					
				}
				
			
				
				try{
					for(int j=0;j<Parameters.getEventMem().get(i).getMemorySituation().size();j++){
						ele = Parameters.getEventMem().get(i).getMemorySituation().get(j);					
						if(!(ele.isEmpty()))
							mem.put(j,(ProcessRequest)ele);
						//else
						//	mem.put(j, new ProcessRequest());
					}
				}catch(Exception e){
					e.printStackTrace();
				}
				
				
				for(int j=0;j<Parameters.getEventMem().get(i).getSwapSituation().size();j++){
					ele = Parameters.getEventMem().get(i).getSwapSituation().get(j);	
					if(!(ele.isEmpty()))
						swap.put(j,(ProcessRequest)ele);
					//else
					//	swap.put(j, null);
				}
				//SimEvent(int PID,String eventType, int PagIn, int PagOut, Hashtable<Integer, ProcessRequest> Mem, Hashtable<Integer, ProcessRequest> Swap,int time){
				events.add(new SimEvent(Parameters.getEventMem().get(i).getProcess().getPID(),
						     Parameters.getEventMem().get(i).getEventType(),
						     Parameters.getEventMem().get(i).getPagIn(),
						     Parameters.getEventMem().get(i).getPagOut(),
						     mem,
						     swap,
						     0));	
			}
			
		}
		
		if (isactiveSimType2()){			
			
				Parameters.setSimulationType(2);			
				CPU cpu = new CPU();
				try{
					cpu.dispacherSecondary();	
				}catch(Exception e){
					e.printStackTrace();
				}
				/*events.add(new SimEvent(1,"Stato Iniziale",1,StatoInizialeMemoriaCentrale(),StatoInizialeMemoriaSwap(),0));  //situazione iniziale memoria centrale
				events.add(new SimEvent(1,"Page Fault",1,3,StatoInizialeMemoriaCentrale(),StatoInizialeMemoriaSwap(),2));
				events.add(new SimEvent(1,"GET",3,MemoriaCentrale1(),MemoriaSwap1(),3));
				events.add(new SimEvent(1,"Page Fault",2,4,MemoriaCentrale1(),MemoriaSwap1(),5));
				events.add(new SimEvent(1,"GET",4,MemoriaCentrale2(),MemoriaSwap2(),6));
				events.add(new SimEvent(3,"GET",4,MemoriaCentrale2a(),MemoriaSwap2(),8));
				*/
				eventsDisk.HDDevents.add(new SimEvent("","/","Stato Inziale","0"));
				
				eventsDisk.HDDstate = new Hashtable<Integer, ArrayList<Integer>>();
				
				eventsDisk.HDDlistFiles= new Hashtable<Integer, ArrayList<String>>();
				
				
				int t=0;
				int count=0;
				
				ArrayList<String> listEventPrec=new ArrayList<String>();
			
				for (int i=0;i<Parameters.getEventHDD().size();i++){			
					
					count=i;


					IMemoryElement ele;
					
					t+=Parameters.getEventHDD().get(i).getTempo();
					//SimEvent(int PID,String eventType, int PagIn, int PagOut, Hashtable<Integer, ProcessRequest> Mem, Hashtable<Integer, ProcessRequest> Swap,int time){
					eventsDisk.HDDevents.add(new SimEvent(Parameters.getEventHDD().get(i).getFile().getName(),
							Parameters.getEventHDD().get(i).getFile().getPath(),
							Parameters.getEventHDD().get(i).getEventType(),
							t+""));	
					
					//eventsDisk.HDDstate.put(count, default1());
					
					
					if (i==0){
						eventsDisk.HDDlistFiles.put(0,default2());
						eventsDisk.HDDstate.put(0, default1());

					}else{
						System.out.println("Dentro l'if n.volte: "+i);
						//for (int j=0;j<i+1;j++)
						
						listEventPrec.add(Parameters.getEventHDD().get(i).getFile().getPath());
						//ArrayList<String> listEventPrecTMP=(ArrayList<String>)listEventPrec.clone();
						eventsDisk.HDDlistFiles.put(i,(ArrayList<String>)listEventPrec.clone());
					}
					
				}
				
				//for (int j=0;j<count+1;j++)
				listEventPrec.add(Parameters.getEventHDD().get(count).getFile().getPath());
			
				eventsDisk.HDDlistFiles.put(count+1,listEventPrec);
				
				
				
				//TABELLA EVENTI DISCO
				/*eventsDisk.HDDevents=new ArrayList<SimEvent>();
					//situazione Iniziale
				eventsDisk.HDDevents.add(new SimEvent("","/","Stato Inziale","0"));
					
				eventsDisk.HDDevents.add(new SimEvent("1.txt","/Disco/prova/1.txt","Scrittura","2")); 
				eventsDisk.HDDevents.add(new SimEvent("2.txt","/Disco/prova/2.txt","Scrittura","4")); 
				eventsDisk.HDDevents.add(new SimEvent("1.txt","/Disco/prova/1.txt","Scrittura","8"));
				eventsDisk.HDDevents.add(new SimEvent("4.txt","/Disco/prova/4.txt","Scrittura","10"));
				eventsDisk.HDDevents.add(new SimEvent("5.txt","/Disco/prova/5.txt","Scrittura","12"));
				eventsDisk.HDDevents.add(new SimEvent("4.txt","/Disco/prova/4.txt","Lettura","13"));
				eventsDisk.HDDevents.add(new SimEvent("fine.txt","/Disco/prova/fine.txt","Scrittura","15"));
				eventsDisk.HDDevents.add(new SimEvent("full","full","Scrittura","15"));
				
				//uno stato dell'HDD
				//al caricamento tenere conto che \per valori inferiori al Mega si considera valore 1.
				
				
				eventsDisk.HDDstate = new Hashtable<Integer, ArrayList<Integer>>();
				eventsDisk.HDDstate.put(0, default1());
				eventsDisk.HDDstate.put(1, Evento1_X());
				eventsDisk.HDDstate.put(2, Evento2_X());
				eventsDisk.HDDstate.put(3, Evento3_X());
				eventsDisk.HDDstate.put(4, Evento4_X());
				eventsDisk.HDDstate.put(5, Evento5_X());
				eventsDisk.HDDstate.put(6, Evento5_X());
				eventsDisk.HDDstate.put(7, Evento6_X());
				eventsDisk.HDDstate.put(8, Evento7_X());
			
				eventsDisk.HDDlistFiles= new Hashtable<Integer, ArrayList<String>>();
				eventsDisk.HDDlistFiles.put(0,default2());
				eventsDisk.HDDlistFiles.put(1,Evento1_Y());
				eventsDisk.HDDlistFiles.put(2,Evento2_Y());
				eventsDisk.HDDlistFiles.put(3,Evento3_Y());
				eventsDisk.HDDlistFiles.put(4,Evento4_Y());
				eventsDisk.HDDlistFiles.put(5,Evento5_Y());
				eventsDisk.HDDlistFiles.put(6,Evento5_Y());
				eventsDisk.HDDlistFiles.put(7,Evento6_Y());
				eventsDisk.HDDlistFiles.put(8,Evento7_Y());*/
		}
		
		
		
		
	}
	
	private ArrayList<Integer> Evento7_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(163840);
		return HDDarea1;
	}
	private ArrayList<String> Evento7_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/S.O.");
		return HDDfiles1;
	}
	
	private ArrayList<Integer> Evento6_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(2500);
		HDDarea1.add(5000);
		HDDarea1.add(500);
		HDDarea1.add(300);
		HDDarea1.add(3000);
		return HDDarea1;
	}
	
	
	private ArrayList<String> Evento6_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/4.txt");
		HDDfiles1.add("/Disco/prova/5.txt");
		HDDfiles1.add("-1");
		HDDfiles1.add("/Disco/prova/2.txt");
		HDDfiles1.add("/Disco/prova/fine.txt");
		return HDDfiles1;
	}
	
	
	private ArrayList<Integer> Evento5_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(2500);
		HDDarea1.add(5000);
		HDDarea1.add(500);
		HDDarea1.add(300);
		return HDDarea1;
	}
	
	
	private ArrayList<String> Evento5_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/4.txt");
		HDDfiles1.add("/Disco/prova/5.txt");
		HDDfiles1.add("-1");
		HDDfiles1.add("/Disco/prova/2.txt");
		return HDDfiles1;
	}
	
	
	private ArrayList<Integer> Evento4_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(2500);
		HDDarea1.add(5500);
		HDDarea1.add(300);
		return HDDarea1;
	}
	
	
	private ArrayList<String> Evento4_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/4.txt");
		HDDfiles1.add("-1");
		HDDfiles1.add("/Disco/prova/2.txt");
		return HDDfiles1;
	}
	
	
	private ArrayList<String> Evento3_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("-1");
		HDDfiles1.add("/Disco/prova/2.txt");
		return HDDfiles1;
	}
	
	private ArrayList<Integer> Evento3_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(8000);
		HDDarea1.add(300);
		return HDDarea1;
	}
	
	private ArrayList<Integer> Evento2_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(8000);
		HDDarea1.add(300);
		return HDDarea1;
	}
	
	private ArrayList<String> Evento2_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/1.txt");
		HDDfiles1.add("/Disco/prova/2.txt");
		return HDDfiles1;
	}
		
	private ArrayList<Integer> Evento1_X() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(8000);
		return HDDarea1;
	}
	
	private ArrayList<String> Evento1_Y() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/1.txt");
		return HDDfiles1;
	}
	
	private ArrayList<String> default2() {
		ArrayList<String> HDDfiles1 = new ArrayList<String>();
		HDDfiles1.add("/Disco");
		HDDfiles1.add("/Disco/prova1");
		HDDfiles1.add("/Disco/prova");
		HDDfiles1.add("/Disco/prova/1.txt");
		return HDDfiles1;
	}

	private ArrayList<Integer> default1() {
		ArrayList<Integer> HDDarea1 = new ArrayList<Integer>();
		HDDarea1.add(2000);
		HDDarea1.add(3000);
		HDDarea1.add(6000);
		HDDarea1.add(5000);
		return HDDarea1;
	}

	public ArrayList<SimEvent> getResult(){
		return events;
	}
	
	public EventsDisk getResult2(){
		return eventsDisk;
	}
	
	private Hashtable<Integer, ProcessRequest> StatoInizialeMemoriaCentrale() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,1,"r"));
		InitMem.put(1, new ProcessRequest(1,2,"r"));
		InitMem.put(2, new ProcessRequest(2,1,"r"));
		InitMem.put(3, new ProcessRequest(2,3,"r"));
		InitMem.put(4, new ProcessRequest(3,3,"r"));
		return InitMem;
	}
	private Hashtable<Integer, ProcessRequest> StatoInizialeMemoriaSwap() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,3,"r"));
		InitMem.put(1, new ProcessRequest(1,4,"r"));
		InitMem.put(2, new ProcessRequest(2,2,"r"));
		InitMem.put(2, new ProcessRequest(2,4,"r"));
		InitMem.put(3, new ProcessRequest(3,1,"r"));
		InitMem.put(4, new ProcessRequest(3,2,"r"));
		InitMem.put(5, new ProcessRequest(3,5,"r"));
		InitMem.put(6, new ProcessRequest(3,6,"r"));
		InitMem.put(7, new ProcessRequest(3,7,"r"));
		return InitMem;
	}

	private Hashtable<Integer, ProcessRequest> MemoriaCentrale1() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,3,"r"));
		InitMem.put(1, new ProcessRequest(1,2,"r"));
		InitMem.put(2, new ProcessRequest(2,1,"r"));
		InitMem.put(3, new ProcessRequest(2,3,"r"));
		InitMem.put(4, new ProcessRequest(3,3,"r"));
		return InitMem;
	}
	
	private Hashtable<Integer, ProcessRequest> MemoriaSwap1() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,1,"r"));
		InitMem.put(1, new ProcessRequest(1,4,"r"));
		InitMem.put(2, new ProcessRequest(2,2,"r"));
		InitMem.put(2, new ProcessRequest(2,4,"r"));
		InitMem.put(3, new ProcessRequest(3,1,"r"));
		InitMem.put(4, new ProcessRequest(3,2,"r"));
		InitMem.put(5, new ProcessRequest(3,5,"r"));
		InitMem.put(6, new ProcessRequest(3,6,"r"));
		InitMem.put(7, new ProcessRequest(3,7,"r"));
		return InitMem;
	}
	private Hashtable<Integer, ProcessRequest> MemoriaCentrale2() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,3,"r"));
		InitMem.put(1, new ProcessRequest(1,4,"r"));
		InitMem.put(2, new ProcessRequest(2,1,"r"));
		InitMem.put(3, new ProcessRequest(2,3,"r"));
		InitMem.put(4, new ProcessRequest(3,3,"r"));
		return InitMem;
	}
	
	private Hashtable<Integer, ProcessRequest> MemoriaSwap2() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,1,"r"));
		InitMem.put(1, new ProcessRequest(1,2,"r"));
		InitMem.put(2, new ProcessRequest(2,2,"r"));
		InitMem.put(2, new ProcessRequest(2,4,"r"));
		InitMem.put(3, new ProcessRequest(3,1,"r"));
		InitMem.put(4, new ProcessRequest(3,2,"r"));
		InitMem.put(5, new ProcessRequest(3,5,"r"));
		InitMem.put(6, new ProcessRequest(3,6,"r"));
		InitMem.put(7, new ProcessRequest(3,7,"r"));
		return InitMem;
	}
	private Hashtable<Integer, ProcessRequest> MemoriaCentrale2a() {
		Hashtable<Integer, ProcessRequest> InitMem = new Hashtable<Integer, ProcessRequest>();
		InitMem.put(0, new ProcessRequest(1,3,"r"));
		InitMem.put(1, new ProcessRequest(1,4,"r"));
		InitMem.put(2, new ProcessRequest(2,1,"r"));
		InitMem.put(3, new ProcessRequest(2,3,"r"));
		InitMem.put(4, new ProcessRequest(3,3,"r"));
		InitMem.put(5, new ProcessRequest(3,4,"r"));
		return InitMem;
	}
}
